/**
 * Vue3中的响应式原理，为什么使用Proxy(代理) 与 Reflect(反射)？
 * 在使用Object.defineProperty的时候，我们遇到的问题有：
 *  1.一次只能对一个属性进行监听，需要遍历来对所有属性监听。
 *  2. 在遇到一个对象的属性还是一个对象的情况下，需要递归监听。
 *  3. 对于对象的新增属性，需要手动监听
 *  4. 对于数组通过push、unshift方法增加的元素，也无法监听
 *  这些问题在Proxy中都轻松得到了解决，让我们看看以下代码。
 */

const person = {
  name: 'Barry',
  age: 22,
  job: {
    city: 'CDC',
    salary: 50
  }
}

// 1.一次只能对一个属性进行监听，需要遍历来对所有属性监听。
// 可以看出，Proxy代理的是整个对象，而不是对象的某个特定属性，不需要我们通过遍历来逐个进行数据绑定
let p = new Proxy(person, {
  get(target, key) {
    return target[key]
  },
  set(target, key, val) {
    return target[key] = val
  }
})
console.log(p)

// 2. 在遇到一个对象的属性还是一个对象的情况下，需要递归监听。
// 可以看到成功的监听到了 person 对象里的 job 对象，job 的所有属性都可以被成功监听到
console.log(p.job);
console.log(p.job.city);
console.log(p.job.salary);

p.job.salary = 40
console.log(p.job.salary) // 40

// 3. 对于对象的新增属性，需要手动监听
// 访问的 p.job.type 就是原对象上不存在的属性，但是我们访问它的时候，仍然可以被 get 拦截到
console.log(p.job.type); // undefined

// 并且也能进行赋值
p.job.type = 'web'
console.log(p.job.type) // web;

// 4. 对于数组通过push、unshift方法增加的元素，也无法监听
const hobby = ['sing', 'dance', 'rap']

let h = new Proxy(hobby, {
  get(target, key) {
    return target[key]
  },
  set(target, key, val) {
    return target[key] = val
  }
})

console.log(h);
console.log(h[0]);

h[0] = 'run'

h.push('play')
console.log(h);

// -------------------------- 以上，我们已经把 Vue2 遇到的问题都完美解决了 ---------------------------